/**********************************************************************\

 Copyright 2012 Diggory Blake

 This file is part of klip-engine

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

\**********************************************************************/
#pragma once

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/XKBlib.h>
#include <X11/extensions/xf86vmode.h>
#include <GL/glx.h>
#include <set>

class kWindowLinux;
class kSystemLinux;

#ifndef KLIP_SYSTEM_DEFAULT
#define KLIP_SYSTEM_DEFAULT
#define KLIP_MAIN() main()
typedef kSystemLinux kSystemDefault;
#endif

#include "ksystem.h"

class kWindowLinux : public kWindow {
	friend class kSystemLinux;
private:
	Window _wnd;
	XVisualInfo* _vi;
	keWindowOptions _options;
	kVec2i _pos;
	kVec2i _size;
	XF86VidModeModeInfo _defaultMode;
	kBasicMouseInput _mouseInput;
	kBasicKeyboardInput _keyboardInput;
	kSystemLinux* _system;

	kWindowLinux(kSystemLinux* system);
	void update();

public:
	~kWindowLinux();

	virtual kHandle getHandle();
	virtual kMouseInput* getMouseInput();
	virtual kKeyboardInput* getKeyboardInput();

	virtual void close();
	virtual void destroy();
	virtual kHandle createGLContext();
	virtual void deleteGLContext(kHandle context);
	virtual void activateGLContext(kHandle context);
	virtual void setOptions(keWindowOptions options);
	virtual void setSize(const kVec2i& size);
	virtual void setPos(const kVec2i& pos);
	virtual void setTitle(const std::tstring& title);
	virtual void swapGLBuffers();
	virtual kVec2i getPos();
	virtual kVec2i getSize();
	virtual keWindowOptions getOptions();
};

class kSystemLinux : public kSystem {
	friend class kWindowLinux;
private:
	struct MotifHints
	{
		unsigned long	flags;
		unsigned long	functions;
		unsigned long	decorations;
		long			inputMode;
		unsigned long	status;
	};

	Display* _display;
	XContext _context;
	Window _root;
	Atom _wm_protocols;
	Atom _wm_delete_window;
	Atom _motif_wm_hints;
	Atom _net_wm_state;
	Atom _net_wm_state_fullscreen;
	std::set<kWindowLinux*> _windows;

	template<int EventType> static Bool waitForEvent_Callback(Display *d, XEvent *e, XPointer arg) {
	   return (e->type == EventType) && (e->xmap.window == (Window)arg);
	}
	template<int EventType> void waitForEvent(kWindowLinux* w) {
		XEvent e;
		XPeekIfEvent(_display, &e, &waitForEvent_Callback<EventType>, (XPointer)w->_wnd);
		onUpdate(0.0f);
	}

protected:
	virtual void onUpdate(float delta);

public:
	kSystemLinux();
	virtual ~kSystemLinux();
	virtual unsigned getTime();
	virtual kWindow* createWindow(const std::tstring& title);
};
